/**
 * Внешний итератор дерева.
 * Используется для обхода элементов дерева.
 * <br/>
 * Хранит указатель на корень и текущий элемент дерева,
 * поэтому операции добавления или удаления элементов дерева не рекомендуется использовать
 * между операцией получения следуюещего элемента.
 * <br/>
 * Является небезопасным в многопоточной среде.
 */

#ifndef _TREEITERATOR_H
#define	_TREEITERATOR_H

#include <iterator>
#include "Tree.h"
#include "TreeNode.h"
#include "TreeException.h"
#include "conf.h"

namespace etu {
namespace tree {

template <typename T> class Tree;

template <typename T>
class TreeIterator : public std::iterator<std::input_iterator_tag, T> {
    
    const Tree<T>* tree;
    InnerTreeIterator<T>* innerIterator;
    TreeNode<T>* currentNode;

public:

    /**
     * Создание итератора для конкретного дерева
     * @param tree дерево
     */
    TreeIterator(const Tree<T>& tree) {
        this->tree = &tree;
        this->innerIterator = new InnerTreeIterator<T>(* this->tree);
        this->currentNode = this->innerIterator->next();
    }

    /**
     * Создание итератора для конкретного дерева
     * @param tree дерево
     */
    TreeIterator(const Tree<T>* tree) {
        this->tree = tree;
        this->innerIterator = new InnerTreeIterator<T>(* this->tree);
        this->currentNode = this->innerIterator->next();
    }

    /**
     * Деструктор
     */
    virtual ~TreeIterator() {
        //
    }

    /**
     * Конструктор копирования. Копирует указатели
     */
    TreeIterator(const TreeIterator<T> &orig) {
        this->innerIterator = orig.innerIterator;
        this->tree = orig.tree;
        this->currentNode = orig.currentNode;
    }

    /**
     * Переход к первому элементу дерева.
     * Текущим элементом становится корень дерева.
     */
    void goToFirst() {
        if(!this->tree.isEmpty()) {
            this->innerIterator->goToFirst();
            this->currentNode = this->innerIterator->next();
        }
    }

    TreeIterator<T>& operator++() {
        next();
        return this;
    }

    bool operator==(const TreeIterator<T>& it) {
        return (it.currentNode == this->currentNode);
    }

    bool operator!=(const TreeIterator<T>& it) {
        return (it.currentNode != this->currentNode);
    }

    T& operator*() {
        return this->currentNode->getValue();
    }

    /**
     * Проверка, имеет ли дерево ещё элементы
     * @return true, если дерево не содержит больше элементов ; иначе false
     */
    bool hasNext() const {
        return (this->currentNode != NULL);
    }

    /**
     * Получение следующего элемента.
     * @return следующий элемент дерева
     * @throws TreeException если дерево больше не содержит элементов
     */
    T next() throw(TreeException) {
        T ret;

        if(!this->hasNext()) {
            throw TreeException("Дерево не содержит больше элементов");
        }

        if(this->currentNode != NULL) {
            ret = this->currentNode->getValue();
        }

        this->currentNode = this->innerIterator->next();
        
        return ret;
    }
};

}
}

#endif	/* _TREEITERATOR_H */
